﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniCT.LinkShareWpf.Interface;
using System.Windows.Forms;
using System.Collections.ObjectModel;
using UniCT.LinkShareWpf.CommunicationChannel;
using UniCT.LinkShareWpf.Model;
using LinkShareWpf.Properties;

namespace LinkShareWpf
{
    public class ConnectionHandler
    {

        #region Private
        private string serviceName;
        private Server server;
        #endregion

        public bool ServerOnLine
        {
            get;
            private set;
        }

        #region Events
        // Ogni modifica alla lista, scateno un evento catturato dai ViewModel
        public event EventHandler UpdateXmlNodesRequest;
        #endregion

        public ConnectionHandler()
        {
            server = new Server();
            serviceName="LinkShareWpf";
        }

        public Uri GetUri(string hostname, int port)
        {
            UriBuilder ub = new UriBuilder(Uri.UriSchemeHttp, hostname, port, serviceName);
            return ub.Uri;
        }

        #region Static
        private static ConnectionHandler instance = null;
        public static ConnectionHandler Instance
        {
            get
            {
                if (instance == null)
                    instance = new ConnectionHandler();
                return instance;
            }
        }
        #endregion


        

        private Node getDeleteNode()
        {
            long max=0;
            Node tempNode = null;
            foreach (Node node in MyNode.Instance.Nodes)
            {
                long ping = Ping(node);
                if (ping == -1)
                    return node;
                else
                {
                    if (ping > max)
                    {
                        max = ping;
                        tempNode = node;
                    }
                }
            }
            return tempNode;
        }

        // Booleano indica la priorita
        // Se è attiva il controllo lo aggiunge sicuramente.
        // Se c'è posto non c'è problema
        // Altriment eliminando quello a ping piu alto
        // perchè l'inserimento è avvenuto 
        // Se la priorità non è attiva
        // Si aggiunge solo se il ping è migliore degli altri
        public void AddNode(Node node, bool priority)
        {
            //Verifichiamo che il nodo sia gia presente
            if (!MyNode.Instance.Contains(node))
            {
                if (priority) 
                {
                    Console.WriteLine("Priorita Alta");
                    // Se la lista è piena eseguo i controlli
                    if (MyNode.Instance.Nodes.Count() == Settings.Default.MaxNode)
                    {
                        Node deletedNode = getDeleteNode();
                        Console.WriteLine(deletedNode.Url + " Sara cancellato");
                        RemoveNode(deletedNode);
                    }
                    // Se non entro dentro l'if la lista non è piena
                    // ed aggiungo comunque
                    MyNode.Instance.Nodes.Add(node);
                    MyNode.Instance.Save();
                    UpdateXmlNodesRequest(this, EventArgs.Empty);
                }
                else
                {
                    Console.WriteLine("Priorita Bassa");
                    if (MyNode.Instance.Nodes.Count() == Settings.Default.MaxNode)
                    {
                        Node deletedNode = getDeleteNode();
                        Console.WriteLine(deletedNode.Url + " Nodo che potrebbe essere eliminato");
                        long ping = Ping(deletedNode);
                        long ping2 = Ping(node);
                        if(ping2<ping && ping2!=-1)
                        {
                            RemoveNode(deletedNode);
                            node.LastPing = ping2;
                            node.LastAliveRequest = DateTime.Now;
                            MyNode.Instance.Nodes.Add(node);
                            MyNode.Instance.Save();
                            UpdateXmlNodesRequest(this, EventArgs.Empty);
                        } 
                    }
                    else // Lista non piena aggiungo sempre
                    {
                        node.LastPing = Ping(node);
                        node.LastAliveRequest = DateTime.Now;
                        MyNode.Instance.Nodes.Add(node);
                        MyNode.Instance.Save();
                        UpdateXmlNodesRequest(this, EventArgs.Empty);
                    }
                }
            }
        }

        public void RemoveNode(Node node)
        {
            MyNode.Instance.Nodes.Remove(node);
            MyNode.Instance.Save();
            UpdateXmlNodesRequest(this, EventArgs.Empty);
        }

        public ObservableCollection<Node> GetNodes()
        {
            return MyNode.Instance.Nodes;
        }

        public long Ping(Node node)
        {
            Client client = new Client(node.Uri);
            long ping = client.PingRequest();
            if(ping!=-1)
                node.LastAliveRequest = DateTime.Now;
             return ping;
        }

        public void Pings()
        {
            Console.WriteLine("Pings()");
            foreach (Node node in   MyNode.Instance.Nodes)
            {
                Console.WriteLine("Provo a fare il ping :" + node.Url);
                node.LastPing = Ping(node);
                UpdateXmlNodesRequest(this, EventArgs.Empty);
            }
            MyNode.Instance.Save();
        }
        
        public void StartServer()
        {
            server.Start();
            ServerOnLine = true;
        }

        public void StopServer()
        {
            server.Stop();
            ServerOnLine = false;
        }
        
        public void SearchResources(NetFilter netFilter)
        {
            foreach (Node node in   MyNode.Instance.Nodes)
            {
                Client client = new Client(node.Uri);
                client.SingleRequest(netFilter);
            }
        }
        
        
    }

}
